using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using NHibernate;
using ObjectModel;

namespace DAL
{
    public class Repository
    {
        #region fields
        ISessionFactory factory;
        #endregion

        #region ctor
        public Repository()
        {
            NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
            cfg.AddAssembly(typeof(Repository).Assembly);

            factory = cfg.BuildSessionFactory();
        }
        #endregion

        #region methods
        public ItemBase GetItemById(Type clazz, int id)
        {
            using (ISession session = OpenSession())
            {
                return (ItemBase)session.Get(clazz, id);

                Repository.CloseSession(session);
            }
        }

        public IList FindByCriteria(string query, Type[] types, object[] values)
        {
            List<NHibernate.Type.IType> nhTypes = new List<NHibernate.Type.IType>();

            foreach (Type type in types)
                nhTypes.Add(Repository.GetNHibernateType(type));

            using (ISession session = OpenSession())
            {
                return session.Find(query, values, nhTypes.ToArray());

                Repository.CloseSession(session);
            }
        }

        public bool ObjectIsInitialized(IList nativeCollection)
        {
            return NHibernateUtil.IsInitialized(nativeCollection);
        }

        public IList ReconnectSession(ItemBase item, IList nativeColl)
        {
            NHibernate.Collection.IPersistentCollection pColl = nativeColl as NHibernate.Collection.IPersistentCollection;

            using (ISession session = OpenSession())
            {
                try
                {
                    if (pColl != null && !pColl.WasInitialized)
                    {
                        //item dirty check skipped [..]

                        session.Lock(item, LockMode.None);

                        NHibernateUtil.Initialize(pColl);
                    }
                }
                catch (NonUniqueObjectException)
                {
                    session.Replicate(item, ReplicationMode.Overwrite);
                    session.Lock(item, LockMode.None);
                    NHibernateUtil.Initialize(pColl);
                }
            }

            return nativeColl;
        }
        #endregion

        #region private members
        private ISession OpenSession()
        {
            return factory.OpenSession();
        }

        private static void CloseSession(ISession session)
        {
            session.Close();
        }

        internal static NHibernate.Type.IType GetNHibernateType(System.Type valueType)
        {

            if (valueType == typeof(System.String))
                return NHibernate.NHibernateUtil.String;

            if (valueType == typeof(System.Int32))
                return NHibernate.NHibernateUtil.Int32;

            if (valueType == typeof(System.Boolean))
                return NHibernate.NHibernateUtil.Boolean;

            if (valueType == typeof(System.DateTime))
                return NHibernate.NHibernateUtil.DateTime;

            if (valueType == typeof(System.Decimal))
                return NHibernate.NHibernateUtil.Decimal;

            if (valueType == typeof(System.Double))
                return NHibernate.NHibernateUtil.Double;

            if (valueType == typeof(System.Guid))
                return NHibernate.NHibernateUtil.Guid;

            if (valueType == typeof(System.Byte))
                return NHibernate.NHibernateUtil.Byte;

            if (valueType == typeof(System.Char))
                return NHibernate.NHibernateUtil.Character;

            if (valueType == typeof(System.Int16))
                return NHibernate.NHibernateUtil.Int16;

            if (valueType == typeof(System.Int64))
                return NHibernate.NHibernateUtil.Int64;

            if (valueType == typeof(System.Single))
                return NHibernate.NHibernateUtil.Single;

            return NHibernate.NHibernateUtil.Entity(valueType);
        }
        #endregion
    }
}
